package ubi.quando.ServerComm;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;

import org.osmdroid.util.GeoPoint;

import ubi.quando.App.Contact;
import ubi.quando.App.ContactWallet;
import ubi.quando.App.EventBase;
import ubi.quando.App.EventMeeting;
import ubi.quando.App.EventPickUp;
import ubi.quando.App.PickUpParticipant;
import ubi.quando.UI.UbiApplication;

import com.google.gson.stream.JsonReader;

public class MyJsonReader {

	private static final int OK = 100;
	private static final int ERROR = 101;

	private static final int LATITUDE = 0;
	private static final int LONGITUDE = 1;

	private static final int CLIENT = 0;
	private static final int EVENT = 1;


	private static UbiApplication mApp;

	public MyJsonReader(UbiApplication mApp){
		this.mApp = mApp;
	}

	public int getCode(BufferedReader rd) throws IOException {
		JsonReader json = new JsonReader(rd);
		json.beginObject();
		while (json.hasNext()) {
			String name = json.nextName();
			if (name.equals("CODE")) {
				return json.nextInt();
				//				if (code == ERROR) {
				//					return false;
				//				} else if (code == OK) {
				//					return OK;
				//				}
			}
		}
		json.endObject();
		return ERROR;
	}

	public String getId(BufferedReader rd, int type) throws IOException {
		String typeName = null;
		switch(type){
		case CLIENT:
			typeName = "client_id";
			break;
		case EVENT:
			typeName = "event_id";
			break;
		default:
			return null;
		}
		JsonReader json = new JsonReader(rd);
		json.beginObject();
		while (json.hasNext()) {
			String name = json.nextName();
			if (name.equals("CODE")) {
				if (json.nextInt() == ERROR) {
					break;
				}
			} else if (name.equals(typeName)) {
				return json.nextString();
			}
		}
		json.endObject();
		return null;
	}

	public ContactWallet getContactWallet(BufferedReader rd) throws IOException {
		JsonReader json = new JsonReader(rd);
		json.beginObject();
		while (json.hasNext()) {
			String name = json.nextName();
			if (name.equals("CODE")) {
				int code = json.nextInt();
				if (code == ERROR) {
					break;
				}
			} else if (name.equals("CLIENT")) {
				return getContactWallet(json);
			}
		}
		json.endObject();
		return null;
	}

	private static ContactWallet getContactWallet(JsonReader json) throws IOException {
		json.beginObject();
		String id = null, name = null;
		ArrayList<Contact> contacts = new ArrayList<Contact>();
		ArrayList<EventBase> events = new ArrayList<EventBase>();
		while (json.hasNext()) {
			String arg = json.nextName();
			if (arg.equals("name")) {
				name = json.nextString();
			} else if (arg.equals("id")) {
				id = json.nextString();
			} else if (arg.equals("contacts")) {
				getContacts(contacts, json);
			} else if (arg.equals("events")) {
				getEvents(events, json);
			} else {
				return null;
			}
		}
		json.endObject();

		return new ContactWallet(id, contacts, events, name);
	}

	private static void getEvents(ArrayList<EventBase> events, JsonReader json)
	throws IOException {
		json.beginArray();
		while (json.hasNext()) {
			json.beginObject();
			String type = json.nextName();
			if (type.equals("MEETING_EVENT")) {
				getMeetingEvent(events, json);
			} else if (type.equals("PICKUP_EVENT")) {
				getPickupEvent(events, json);
			}
			json.endObject();
		}
		json.endArray();
	}

	private static void getMeetingEvent(ArrayList<EventBase> events, JsonReader json)
	throws IOException {
		String id = null, name = null, /* destName = null, */creatorId = null, arg = null;
		boolean started = false;
		long time = 0;
		GeoPoint dest = null;
		ArrayList<Contact> participants = new ArrayList<Contact>();
		ArrayList<EventBase> pickups = new ArrayList<EventBase>();

		json.beginObject();
		while (json.hasNext()) {
			arg = json.nextName();
			if (arg.equals("id")) {
				id = json.nextString();
			} else if (arg.equals("name")) {
				name = json.nextString();
			}/*
			 * else if(arg.equals("destName")){ destName = json.nextString(); }
			 */else if (arg.equals("dest")) {
				 String[] latlng = json.nextString().split(",");
				 dest = new GeoPoint(Integer.parseInt(latlng[LATITUDE]),
						 Integer.parseInt(latlng[LONGITUDE]));
			 } else if (arg.equals("creator")) {
				 creatorId = json.nextString();
			 } else if (arg.equals("time")) {
				 time = json.nextLong();
			 } else if (arg.equals("started")) {
				 started = json.nextBoolean();
			 } else if (arg.equals("participants")) {
				 getContacts(participants, json);
			 } else if (arg.equals("pickups")) {
				 getEvents(pickups, json);
			 }
		}
		json.endObject();

		EventMeeting event = new EventMeeting(dest, new Date(time), creatorId,
				participants);
		event.setId(id);
		event.SetName(name);
		event.setStarted(started);
		for (EventBase pickup : pickups) {
			event.addPickUp((EventPickUp) pickup);
		}
		events.add(event);
	}

	private static void getPickupEvent(ArrayList<EventBase> events, JsonReader json)
	throws IOException {
		String id = null, name = null, /* destName = null, */pickerId = null, creatorId = null, arg = null;
		boolean started = false;
		long time = 0;
		GeoPoint dest = null, location = null;
		ArrayList<PickUpParticipant> participants = new ArrayList<PickUpParticipant>();

		json.beginObject();
		while (json.hasNext()) {
			arg = json.nextName();
			if (arg.equals("id")) {
				id = json.nextString();
			} else if (arg.equals("name")) {
				name = json.nextString();
			}/*
			 * else if(arg.equals("destName")){ destName = json.nextString(); }
			 */else if (arg.equals("dest")) {
				 String[] latlng = json.nextString().split(",");
				 dest = new GeoPoint(Integer.parseInt(latlng[LATITUDE]),
						 Integer.parseInt(latlng[LONGITUDE]));
			 } else if (arg.equals("location")) {
				 String locationStr = json.nextString();
				 if (locationStr.equals("none")) {
					 location = null;
				 } else {
					 String[] latlng = locationStr.split(",");
					 location = new GeoPoint(Integer.parseInt(latlng[LATITUDE]),
							 Integer.parseInt(latlng[LONGITUDE]));
				 }
			 } else if (arg.equals("pickerId")) {
				 pickerId = json.nextString();
			 } else if (arg.equals("creator")) {
				 creatorId = json.nextString();
			 } else if (arg.equals("time")) {
				 time = json.nextLong();
			 } else if (arg.equals("started")) {
				 started = json.nextBoolean();
			 } else if (arg.equals("participants")) {
				 getPickUpParticipants(participants, json);
			 }
		}
		json.endObject();

		EventPickUp event = new EventPickUp(dest, new Date(time), creatorId,
				pickerId, participants);
		event.setId(id);
		event.SetName(name);
		event.SetPickUpLocation(location);
		event.setStarted(started);
		events.add(event);
	}

	private static void getPickUpParticipants(
			ArrayList<PickUpParticipant> participants, JsonReader json)
	throws IOException {
		String id = null, location = null, locName = null, arg = null;
		long time = 0;
		json.beginArray();
		while (json.hasNext()) {
			json.beginObject();
			if (json.nextName().equals("PICKUP_CONTACT")) {
				json.beginObject();
				while (json.hasNext()) {
					arg = json.nextName();
					if (arg.equals("id")) {
						id = json.nextString();
					} else if (arg.equals("locName")) {
						locName = json.nextString();
					} else if (arg.equals("location")) {
						location = json.nextString();
					} else if (arg.equals("time")) {
						time = Long.parseLong(json.nextString());
					}
				}
				json.endObject();
			}
			json.endObject();
			String[] latlng = location.split(",");
			GeoPoint gLocation = new GeoPoint(
					Integer.parseInt(latlng[LATITUDE]),
					Integer.parseInt(latlng[LONGITUDE]));
//			Contact contact = mApp.getContactById(id);
			PickUpParticipant participant = new PickUpParticipant(gLocation,
					new Date(time), null);
			participant.setLocName(locName);
			participants.add(participant);
		}
		json.endArray();
	}

	private static void getContacts(ArrayList<Contact> contacts, JsonReader json)
	throws IOException {
		json.beginArray();
		while (json.hasNext()) {
			json.beginObject();
			if (json.nextName().equals("CONTACT")) {
				contacts.add(parseContact(json));
			}
			json.endObject();
		}
		json.endArray();
	}

	public EventMeeting getMeetingEvent(BufferedReader rd)
	throws IOException {
		String id = null, name = null, creator = null;
		long time = 0;
		GeoPoint dest = null;
		boolean started = false;
		ArrayList<Contact> participants = new ArrayList<Contact>();
		ArrayList<EventPickUp> pickups = new ArrayList<EventPickUp>();

		JsonReader json = new JsonReader(rd);
		json.beginObject();
		if (json.nextName().equals("MEETING_EVENT")) {
			json.beginObject();
			while (json.hasNext()) {
				String title = json.nextName();
				if (title.equals("id")) {
					id = json.nextString();
				} else if (title.equals("name")) {
					name = json.nextString();
				} else if (title.equals("dest")) {
					String[] latlng = json.nextString().split(",");
					dest = new GeoPoint(Integer.parseInt(latlng[LATITUDE]),
							Integer.parseInt(latlng[LONGITUDE]));
				} else if (title.equals("creator")) {
					creator = json.nextString();
				} else if (title.equals("time")) {
					time = json.nextLong();
				} else if (title.equals("started")) {
					started = json.nextBoolean();
				} else if (title.equals("participants")) {
					participants = parseParticipants(json);
				} else if (title.equals("pickups")) {
					pickups = parsePickups(json);
				}
			}
		} else {
			return null;
		}
		json.endObject();
		EventMeeting event = new EventMeeting(dest, new Date(time), creator,
				participants);
		event.setPickUps(pickups);
		event.setStarted(started);
		event.setId(id);
		event.SetName(name);
		return event;
	}

	private ArrayList<EventPickUp> parsePickups(JsonReader json)
	throws IOException {
		ArrayList<EventPickUp> pickups = new ArrayList<EventPickUp>();
		json.beginArray();
		while (json.hasNext()) {
			pickups.add(getPickupEvent(json));
		}
		json.endArray();
		return pickups;
	}

	public EventPickUp getPickupEvent(JsonReader json) throws IOException {
		String id = null, name = null, creator = null, picker = null;
		long time = 0;
		GeoPoint dest = null, location = null;
		boolean started = false;
		ArrayList<PickUpParticipant> participants = new ArrayList<PickUpParticipant>();

		json.beginObject();
		if (json.nextName().equals("PICKUP_EVENT")) {
			json.beginObject();			
			while (json.hasNext()) {
				String title = json.nextName();
				if (title.equals("id")) {
					id = json.nextString();
				} else if (title.equals("name")) {
					name = json.nextString();
				} else if (title.equals("dest")) {
					String[] latlng = json.nextString().split(",");
					dest = new GeoPoint(Integer.parseInt(latlng[LATITUDE]),
							Integer.parseInt(latlng[LONGITUDE]));
				} else if (title.equals("location")) {
					String locationStr = json.nextString();
					if (locationStr.equals("none")) {
						location = null;
					} else {
						String[] latlng = locationStr.split(",");
						location = new GeoPoint(Integer.parseInt(latlng[LATITUDE]),
								Integer.parseInt(latlng[LONGITUDE]));
					}
				}else if (title.equals("creator")) {
					creator = json.nextString();
				} else if (title.equals("pickerId")) {
					picker = json.nextString();
				} else if (title.equals("time")) {
					time = json.nextLong();
				} else if (title.equals("started")) {
					started = json.nextBoolean();
				} else if (title.equals("participants")) {
					participants = parsePickupParticipants(json);
				}
			}
		} else {
			return null;
		}
		json.endObject();
		EventPickUp event = new EventPickUp(dest, new Date(time), creator,
				picker, participants);
		event.setStarted(started);
		event.setId(id);
		event.SetName(name);
		event.SetPickUpLocation(location);
		return event;
	}

	private ArrayList<PickUpParticipant> parsePickupParticipants(JsonReader json)
	throws IOException {
		ArrayList<PickUpParticipant> participants = new ArrayList<PickUpParticipant>();

		json.beginArray();
		while (json.hasNext()) {
			json.beginObject();
			if (json.nextName().equals("PICKUP_CONTACT"))
				participants.add(parsePickUpContact(json));
			json.endObject();
		}
		json.endArray();
		return participants;
	}

	private PickUpParticipant parsePickUpContact(JsonReader json)
	throws IOException {
		String name = null, id = null, email = null, locName = null;
		GeoPoint location = null;
		long time = 0;
		json.beginObject();
		while (json.hasNext()) {
			String title = json.nextName();
			if (title.equals("id")) {
				id = json.nextString();
			} else if (title.equals("name")) {
				name = json.nextString();
			} else if (title.equals("location")) {
				String[] latlng = json.nextString().split(",");
				location = new GeoPoint(Integer.parseInt(latlng[LATITUDE]),
						Integer.parseInt(latlng[LONGITUDE]));
			} else if (title.equals("email")) {
				email = json.nextString();
			} else if (title.equals("locName")) {
				locName = json.nextString();
			} else if (title.equals("time")) {
				time = json.nextLong();
			}
		}
		json.endObject();
		PickUpParticipant contact = new PickUpParticipant(location, new Date(
				time), id);
		contact.setLocName(locName);
		contact.setEmail(email);
		contact.setName(name);
		return contact;
	}

	private ArrayList<Contact> parseParticipants(JsonReader json)
	throws IOException {
		ArrayList<Contact> participants = new ArrayList<Contact>();

		json.beginArray();
		while (json.hasNext()) {
			json.beginObject();
			if (json.nextName().equals("CONTACT"))
				participants.add(parseContact(json));
			json.endObject();
		}
		json.endArray();
		return participants;
	}
	
	public static Contact parseContact(JsonReader json) throws IOException {
		String name = null, id = null, email = null;
		GeoPoint location = null;

		json.beginObject();
		while (json.hasNext()) {
			String title = json.nextName();
			if (title.equals("id")) {
				id = json.nextString();
			} else if (title.equals("name")) {
				name = json.nextString();
			} else if (title.equals("location")) {
				String[] latlng = json.nextString().split(",");
				location = new GeoPoint(Integer.parseInt(latlng[LATITUDE]),
						Integer.parseInt(latlng[LONGITUDE]));
			} else if (title.equals("email")) {
				email = json.nextString();
			}
		}
		json.endObject();
		Contact contact = new Contact(name, id, location);
		contact.setEmail(email);
		return contact;
	}

}
